package cn.xshi.oauth.util;

import java.util.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import cn.xshi.oauth.dao.OauthAccountRoleDao;
import cn.xshi.oauth.dao.OauthFunctionRoleDao;
import cn.xshi.oauth.model.OauthAccount;
import cn.xshi.oauth.model.OauthAccountRole;
import cn.xshi.oauth.model.OauthFunctionRole;
import cn.xshi.oauth.service.OauthAccountService;
import cn.xshi.common.base.BaseHttpSessionEntity;
import cn.xshi.common.constant.SessionConstant;
import cn.xshi.common.idgeneration.UUID;
import cn.xshi.common.session.HttpSessionUtils;
import cn.xshi.common.util.ExceptionUtil;
import cn.xshi.common.util.JsonUtil;
import cn.xshi.common.util.SpringUtils;
import cn.xshi.common.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Repository;
import org.springframework.util.CollectionUtils;
/**
 * @Desc OauthUtil
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Repository
@Slf4j
public class OauthUtil{

	@Resource
	HttpSessionUtils httpSessionUtils;

	@Resource
	private OauthFunctionRoleDao oauthFunctionRoleDao;

	@Resource
	private OauthAccountRoleDao oauthAccountRoleDao;

	/**
	 * 读取 JSESSION-ID
	 * @param request
	 * @return
	 */
	public static final String getJSessionId(HttpServletRequest request) {
		HttpHeaders headers = new HttpHeaders();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
		  String key = (String) headerNames.nextElement();
		  String value = request.getHeader(key);
		  headers.add(key, value);
		}
		String sessionId = request.getHeader(SessionConstant.SESSIONID);
		return sessionId;
	}

	/**
	 * 读取 TOKEN
	 * @param request
	 * @return
	 */
	public static final String getTokenId(HttpServletRequest request) {
		HttpHeaders headers = new HttpHeaders();
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String key = (String) headerNames.nextElement();
			String value = request.getHeader(key);
			headers.add(key, value);
		}
		String token = request.getHeader(SessionConstant.TOKEN);
		return token;
	}

	/**
	 * 创建token并返回token
	 * @param tokenInfo = baseHttpSessionEntity
	 * @return
	 */
	public String createToken(String tokenInfo) {
		try {
			JwtUtil jwtUtil = new JwtUtil();
			Map<String, Object> map =  new HashMap<String, Object>();
	    	map.put("clientid", UUID.toUUID());
	    	String token = jwtUtil.createJwtToken(map);
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,1)){
				return token;
			}
			return null;
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}

	/**
	 * 创建token并返回token
	 * @param tokenInfo = baseHttpSessionEntity
	 * @param times
	 * @return
	 */
	public String createToken(String tokenInfo,Integer times) {
		try {
			JwtUtil jwtUtil = new JwtUtil();
			Map<String, Object> map =  new HashMap<String, Object>();
			map.put("clientid", UUID.toUUID());
			String token = jwtUtil.createJwtToken(map);
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,times)){
				return token;
			}
			return null;
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}

	/**
	 * 创建token并返回token
	 * @param clientId（用户id）
	 * @param tokenInfo
	 * @return
	 */
	public String createToken(String clientId, String tokenInfo) {
		try {
			if(StringUtils.isEmpty(clientId)){
				throw new ExceptionUtil("未能获取到clientId");
			}
			JwtUtil jwtUtil = new JwtUtil();
			Map<String, Object> map =  new HashMap<String, Object>();
	    	map.put("clientid", clientId);
	    	String token = jwtUtil.createJwtToken(map);
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,1)){
				return token;
			}
			return null;
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}
	/**
	 * 创建token并返回token
	 * @param clientId（用户id）
	 * @param tokenInfo
	 * @param times
	 * @return
	 */
	public String createToken(String clientId, String tokenInfo,Integer times) {
		try {
			if(StringUtils.isEmpty(clientId)){
				throw new ExceptionUtil("未能获取到clientId");
			}
			JwtUtil jwtUtil = new JwtUtil();
			Map<String, Object> map =  new HashMap<String, Object>();
			map.put("clientid", clientId);
			String token = jwtUtil.createJwtToken(map);
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,times)){
				return token;
			}
			return null;
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}
	
	/**
	 * 创建token并返回token+tokeninfo
	 * @param clientId（用户id）
	 * @param tokenInfo
	 * @return
	 */
	public Map<String,Object> createTokenFn(String clientId, String tokenInfo) {
		try {
			if(StringUtils.isEmpty(clientId)){
				throw new ExceptionUtil("未能获取到clientId");
			}
			JwtUtil jwtUtil = new JwtUtil();
			Map<String, Object> map =  new HashMap<String, Object>();
	    	map.put("clientid", clientId);
	    	String token = jwtUtil.createJwtToken(map);
	    	map =  new HashMap<String, Object>();
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,1)){
				map.put("Token", token);
				map.put("TokenInfo", tokenInfo);
			}
			return map;
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}

	/**
	 * 创建token并返回token+tokeninfo
	 * @param clientId（用户id）
	 * @param tokenInfo
	 * @param times
	 * @return
	 */
	public Map<String,Object> createTokenFn(String clientId, String tokenInfo,Integer times) {
		try {
			if(StringUtils.isEmpty(clientId)){
				throw new ExceptionUtil("未能获取到clientId");
			}
			JwtUtil jwtUtil = new JwtUtil();
			Map<String, Object> map =  new HashMap<String, Object>();
			map.put("clientid", clientId);
			String token = jwtUtil.createJwtToken(map);
			map =  new HashMap<String, Object>();
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,times)){
				map.put("Token", token);
				map.put("TokenInfo", tokenInfo);
				httpSessionUtils.setAttributeExpTime(SessionConstant.ACCOUNT_STORE_PATH+clientId, token,times);//单独存放Account编号维护Token
			}
			return map;
		} catch (Exception e) {
			throw new ExceptionUtil(e.getMessage(),e.getCause());
		}
	}
	
	
	/**
	 * 销毁token
	 * @param request
	 * @return
	 */
	public boolean destory(HttpServletRequest request) {
		String token = getTokenId(request);
		if(StringUtils.isEmpty(token)){
			throw new ExceptionUtil("未能获取到token");
		}
		BaseHttpSessionEntity baseHttpSessionEntity = JsonUtil.fromAliFastJson(getTokenInfo(token), BaseHttpSessionEntity.class);
		boolean flag = httpSessionUtils.del(SessionConstant.TOKEN_STORE_PATH+token);
		if(flag){
			if(null != baseHttpSessionEntity && null != baseHttpSessionEntity.getOauthAccountEntity()){
				String accountId = baseHttpSessionEntity.getOauthAccountEntity().getId();
				flag = httpSessionUtils.del(SessionConstant.ACCOUNT_STORE_PATH+accountId);
			}
		}
		return flag;
	}

	/**
	 * 删除token
	 * @param token
	 * @return
	 */
	public boolean deleteToken(String token) {
		if(StringUtils.isEmpty(token)){
			throw new ExceptionUtil("未能获取到token");
		}
		BaseHttpSessionEntity baseHttpSessionEntity = JsonUtil.fromAliFastJson(getTokenInfo(token), BaseHttpSessionEntity.class);
		boolean flag = httpSessionUtils.del(SessionConstant.TOKEN_STORE_PATH+token);
		if(flag){
			if(null != baseHttpSessionEntity && null != baseHttpSessionEntity.getOauthAccountEntity()){
				String accountId = baseHttpSessionEntity.getOauthAccountEntity().getId();
				flag = httpSessionUtils.del(SessionConstant.ACCOUNT_STORE_PATH+accountId);
			}
		}
		return flag;
	}

	/**
	 * 获取tokeninfo信息
	 * @param token
	 * @return
	 */
	public String getTokenInfo(String token) {
		return httpSessionUtils.getAttribute(SessionConstant.TOKEN_STORE_PATH+token);
	}
	
	/**
	 * 获取token信息
	 * @param request
	 * @return
	 */
	public String getTokenInfo(HttpServletRequest request){
		String token = getTokenId(request);
		if(StringUtils.isEmpty(token)){
			return null;
		}
		return getTokenInfo(token);
	}

	/**
	 * 根据accountId获取token
	 * @param accountId
	 * @return
	 */
	public String getTokenByAccountId(String accountId){
		if(StringUtils.isEmpty(accountId)){
			return null;
		}
		String token = httpSessionUtils.getAttribute(SessionConstant.ACCOUNT_STORE_PATH+accountId);
		return token;
	}

	/**
	 * 根据Token更新内容
	 * @param clientId
	 * @param token
	 * @param tokenInfo
	 * @param times
	 * @return
	 */
	public boolean updateTokenInfoByToken(String clientId, String token,String tokenInfo,int times){
		boolean result = true;
		try {
			if(httpSessionUtils.setAttributeExpTime(SessionConstant.TOKEN_STORE_PATH+token, tokenInfo,times)){
				httpSessionUtils.setAttributeExpTime(SessionConstant.ACCOUNT_STORE_PATH+clientId, token,times);//单独存放Account编号维护Token
			}
		}catch (Exception e){
			log.error("更新Token信息异常{}",e);
			result = false;
		}
		return result;
	}

	/**
	 * 处理其他设备登录同一账户
	 * @param accountId
	 * @param baseHttpSessionEntity
	 * @return
	 */
	public String doLastToken(String accountId,String baseHttpSessionEntity){
		String token = null;
		String lastToken = getTokenByAccountId(accountId);//获取账户中Token信息
		if(!StringUtil.isEmpty(lastToken)){
			//根据账户中Token查询Token原Token对象
			String lastTokenInfo = getTokenInfo(lastToken);
			if(!StringUtil.isEmpty(lastTokenInfo)){
				boolean res = updateTokenInfoByToken(accountId,lastToken,baseHttpSessionEntity,12);
				if(res){
					token = lastToken;
				}
			}
		}
		return token;
	}

	/**
	 *
	 */
	class AccountThread extends Thread{
		List<OauthAccount> oauthAccounts = new ArrayList<>();//用户是否变化

		public AccountThread(){

		}

		public AccountThread(List<OauthAccount> oauthAccounts){
			this.oauthAccounts = oauthAccounts;
		}

		/**
		 * 执行线程
		 */
		public void run() {
			for(OauthAccount oauthAccount: oauthAccounts){
				try {
					String token = httpSessionUtils.getAttribute(SessionConstant.ACCOUNT_STORE_PATH+oauthAccount.getId());//获取该账号已经创建的token
					if(StringUtil.isEmpty(token)){
						continue;
					}
					String baseHttpSessionEntityJson = getTokenInfo(token);
					if(!StringUtils.isEmpty(baseHttpSessionEntityJson)){
						BaseHttpSessionEntity baseHttpSessionEntity = JsonUtil.fromAliFastJson(baseHttpSessionEntityJson, BaseHttpSessionEntity.class);
						if(null != baseHttpSessionEntity.getOauthAccountEntity()){
							baseHttpSessionEntity.getOauthAccountEntity().setInfoBody(oauthAccount.getInfoBody());
						}
						doLastToken(oauthAccount.getId(),JsonUtil.toFastJson(baseHttpSessionEntity));
					}
				}catch (Exception e){
					log.error("登录状态用户基本信息更新失败：{}-{}",e,oauthAccount);
				}
			}
		}
	}

	/**
	 * 内部线程类
	 *
	 *  处理Token变更信息
	 */
	class ResourcesThread extends Thread{

		String roleId;

		List<String> accountIdList = new ArrayList<>();//用户是否变化

		public ResourcesThread(){

		}

		public ResourcesThread(String roleId){
			this.roleId = roleId;
		}

		public ResourcesThread(String roleId,List<String>  accountIdList){

			this.roleId = roleId;

			this.accountIdList = accountIdList;

		}

		public void run() {
			try {
				Map<String,Object> condition = new HashMap<>();
				if(CollectionUtils.isEmpty(accountIdList)){
					accountIdList = new ArrayList<>();
					condition.put("roleId",roleId);
					List<OauthAccountRole> oauthAccountRoles = oauthAccountRoleDao.getOauthAccountRoleListByCondition(condition);
					if(!CollectionUtils.isEmpty(oauthAccountRoles)){
						for(OauthAccountRole oauthAccountRole:oauthAccountRoles){//获取角色下的所有用户
							String accountId = oauthAccountRole.getAccountId();
							accountIdList.add(accountId);
						}
					}
				}
				if(!CollectionUtils.isEmpty(accountIdList)){
					for(String accountId:accountIdList){
						String token = httpSessionUtils.getAttribute(SessionConstant.ACCOUNT_STORE_PATH+accountId);//获取该账号已经创建的token
						if(StringUtil.isEmpty(token)){
							continue;
						}
						OauthAccountService oauthAccountService = SpringUtils.getBean(OauthAccountService.class);
						OauthAccount oauthAccount = oauthAccountService.getOauthAccountById(accountId);//获取更新后的账户信息

						StringBuffer sbf = new StringBuffer();
						condition = new HashMap<>();
						condition.put("accountId",accountId);
						//TODO 处理角色
						List<OauthAccountRole> urList = oauthAccountRoleDao.getOauthAccountRoleListByCondition(condition);
						for(int i = 0; i < urList.size(); i++){
							OauthAccountRole oauthAccountRole = urList.get(i);
							if(null != sbf && !StringUtil.isEmpty(sbf.toString())){
								sbf.append(","+oauthAccountRole.getRoleId());
							}else{
								sbf.append(oauthAccountRole.getRoleId());
							}
						}
						roleId = sbf.toString();
						//TODO 处理功能
						List<OauthFunctionRole> oauthFunctionRoleList = new ArrayList<OauthFunctionRole>();
						if(!StringUtils.isEmpty(roleId.toString())){
							/////////////根据角色集合查找该用户下所有功能
							condition = new HashMap<String, Object>();
							condition.put("roleId", roleId.toString().split(","));
							oauthFunctionRoleList = oauthFunctionRoleDao.getOauthFunctionRoleListByCondition(condition);
						}
						Map<String,String> oauthFunctionInfoUrlMap = new HashMap<>();
						Map<String,String> oauthFunctionInfoMethodMap = new HashMap<>();
						for(OauthFunctionRole oauthFunctionRole:oauthFunctionRoleList){
							oauthFunctionInfoUrlMap.put(oauthFunctionRole.getUrl(),oauthFunctionRole.getUrl());
							oauthFunctionInfoMethodMap.put(oauthFunctionRole.getMethod(),oauthFunctionRole.getMethod());
						}

						String baseHttpSessionEntityJson = getTokenInfo(token);
						if(!StringUtils.isEmpty(baseHttpSessionEntityJson)){
							BaseHttpSessionEntity baseHttpSessionEntity = JsonUtil.fromAliFastJson(baseHttpSessionEntityJson, BaseHttpSessionEntity.class);
							if(null != baseHttpSessionEntity.getOauthAccountEntity()){
								baseHttpSessionEntity.getOauthAccountEntity().setInfoBody(oauthAccount.getInfoBody());
							}
							baseHttpSessionEntity.getOauthFunctionInfoUrlMap().clear();
							baseHttpSessionEntity.getOauthFunctionInfoMethodMap().clear();
							baseHttpSessionEntity.getOauthFunctionInfoUrlMap().putAll(oauthFunctionInfoUrlMap);
							baseHttpSessionEntity.getOauthFunctionInfoMethodMap().putAll(oauthFunctionInfoMethodMap);
							baseHttpSessionEntity.setRoleId(roleId);
							doLastToken(accountId,JsonUtil.toFastJson(baseHttpSessionEntity));
						}
					}
				}
			}catch (Exception e){
				log.error("更新Token异常：{}",e);
			}
		}
	}

	/**
	 *  处理当前角色下已经登录的用户资源功能权限
	 * @param roleId
	 */
	public void doTokenResources( String roleId,List<String> accountIdList){
		if(StringUtil.isEmpty(roleId) && null  == accountIdList && accountIdList.isEmpty()){
			return;
		}
		new Thread(new ResourcesThread(roleId,accountIdList)).start();
	}

	/**
	 *  同步登录状态的用户基本信息
	 * @param oauthAccounts
	 */
	public void doTokenAccount( List<OauthAccount> oauthAccounts){
		if(null  == oauthAccounts && oauthAccounts.isEmpty()){
			return;
		}
		new Thread(new AccountThread(oauthAccounts)).start();
	}
}
